#include "SWFStructs.h"
#include "SWFOutputStream.h"
#include <assert.h>

extern int minBits(int number, int bits);

void EndShapeRecord::encode( SWFOutputStream* stream, UI8 tagCode, ShapeWithStyle* style ) const 
{
	stream->writeUB(TypeFlag, 1);
	stream->writeUB(0, 5);
	/*
	stream->writeUB(0, 1);
	stream->writeUB(0, 1);
	stream->writeUB(0, 1);
	stream->writeUB(0, 1);
	stream->writeUB(0, 1);
	*/
}

void StyleChangeRecord::encode( SWFOutputStream* stream, UI8 tagCode, ShapeWithStyle* style ) const 
{
	stream->writeUB(TypeFlag, 1);
	stream->writeUB(StateNewStyles, 1);
	stream->writeUB(StateLineStyle, 1);
	stream->writeUB(StateFillStyle1, 1);
	stream->writeUB(StateFillStyle0, 1);
	stream->writeUB(StateMoveTo, 1);

	if (StateMoveTo)
	{
		stream->writeUB(MoveBits, 5);
		stream->writeSB(MoveDeltaX, MoveBits);
		stream->writeSB(MoveDeltaY, MoveBits);
	}

	if (StateFillStyle0)
	{
		stream->writeUB(FillStyle0, style->NumFillBits);
	}

	if (StateFillStyle1)
	{
		stream->writeUB(FillStyle1, style->NumFillBits);
	}

	if (StateLineStyle)
	{
		stream->writeUB(LineStyle, style->NumLineBits);
	}

	if (StateNewStyles)
	{
		stream->alignBits();
		FillStyles->encode(stream, tagCode);
		LineStyles->encode(stream, tagCode);

		UB NumFillBits = minBits(FillStyles->FillStyles.size(), 0);
		UB NumLineBits = minBits(LineStyles->LineStyles.size(), 0);

		stream->writeUB(NumFillBits, 4);
		stream->writeUB(NumLineBits, 4);
		style->NumFillBits = NumFillBits;
		style->NumLineBits = NumLineBits;
	}
}

void StraightEdgeRecord::encode( SWFOutputStream* stream, UI8 tagCode, ShapeWithStyle* style ) const 
{
	stream->writeUB(TypeFlag, 1);
	stream->writeUB(StraightFlag, 1);
	stream->writeUB(NumBits - 2, 4);
	stream->writeUB(GeneralLineFlag, 1);
	if (GeneralLineFlag == 0)
		stream->writeUB(VertLineFlag, 1);
	if (GeneralLineFlag == 1 || VertLineFlag == 0)
		stream->writeSB(DeltaX, NumBits);
	if (GeneralLineFlag == 1 || VertLineFlag == 1)
		stream->writeSB(DeltaY, NumBits);
}

void CurvedEdgeRecord::encode( SWFOutputStream* stream, UI8 tagCode, ShapeWithStyle* style ) const 
{
	stream->writeUB(TypeFlag, 1);
	stream->writeUB(StraightFlag, 1);
	stream->writeUB(NumBits - 2, 4);
	stream->writeSB(ControlDeltaX, NumBits);
	stream->writeSB(ControlDeltaY, NumBits);
	stream->writeSB(AnchorDeltaX, NumBits);
	stream->writeSB(AnchorDeltaY, NumBits);
}

void FillStyle::encode( SWFOutputStream* stream, UI8 tagCode ) const
{
	stream->writeUI8(FillStyleType);
	//Color
	if (this->FillStyleType == 0x00)
	{
		switch (tagCode)
		{
		case DefineShape:
		case DefineShape2:
			stream->writeColorRGB(this->Color);
			break;
		case DefineShape3:
		case DefineShape4:
			stream->writeColorRGBA(this->Color);
			break;
		}
	}

	//GradientMatrix
	if (this->FillStyleType == 0x10 ||
		this->FillStyleType == 0x12 ||
		this->FillStyleType == 0x13)
	{
		stream->writeMatrix(this->GradientMatrix);
	}

	//Gradient
	if (this->FillStyleType == 0x10 ||
		this->FillStyleType == 0x12)
	{
		//TODO
		assert(false);
	}
	else if (this->FillStyleType == 0x13)
	{
		//FocalGradient;
		assert(false);
	}

	//Bitmap id
	if (this->FillStyleType == 0x40 ||
		this->FillStyleType == 0x41 ||
		this->FillStyleType == 0x42 ||
		this->FillStyleType == 0x43)
	{
		stream->writeUI16(this->BitmapId);
		stream->writeMatrix(this->BitmapMatrix);
	}
}

void FillStyleArray::encode( SWFOutputStream* stream, UI8 tagCode ) const
{
	UI8 count = FillStyles.size();
	if (count >= 0xff)
	{
		stream->writeUI8(0xff);
		stream->writeUI16(count);
	}
	else
	{
		stream->writeUI8(count);
	}
	for (auto& style : FillStyles)
	{
		style->encode(stream, tagCode);
	}
}

void LineStyle::encode( SWFOutputStream* stream, UI8 tagCode ) const
{
	if (tagCode == DefineShape4)
	{
		assert(false);
	}
	else
	{
		stream->writeUI16(Width);
		if (tagCode == DefineShape3)
			stream->writeColorRGBA(Color);
		else
			stream->writeColorRGB(Color);
	}
}

void LineStyle2::encode( SWFOutputStream* stream, UI8 tagCode ) const 
{
	assert(false);
}

void LineStyleArray::encode( SWFOutputStream* stream, UI8 tagCode ) const
{
	UI8 count = LineStyles.size();
	if (count >= 0xff)
	{
		stream->writeUI8(0xff);
		stream->writeUI16(count);
	}
	else
	{
		stream->writeUI8(count);
	}
	for (auto& style : LineStyles)
	{
		style->encode(stream, tagCode);
	}
}

void Gradient::encode( SWFOutputStream* stream, UI8 tagCode ) const
{
	assert(false);
}

void FocalGradient::encode( SWFOutputStream* stream, UI8 tagCode ) const 
{
	assert(false);
}
